package com.guli.cart.interceptor;
/*
 * @Author 罗俊
 * @date 2020/11/8 - 9:09 上午
 *
 */

import com.guli.common.pojo.vo.UserInfoVo;
import com.guli.common.constant.AuthServerConstant;
import com.guli.common.constant.CartConstant;
import com.guli.common.to.MemberTo;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.UUID;

/**
 * 拦截器：在执行目标方法之前，判断用户的登陆状态（是临时用户还是已登陆用户），
 * 并传递给目标请求
 * <p>
 * 不能将拦截器直接放入 IOC 容器，而是要将 进行配置
 */
//@Component
public class CartInterceptor implements HandlerInterceptor {

    public static final ThreadLocal<UserInfoVo> THREAD_LOCAL = new ThreadLocal<>();

    /**
     * 目标方法执行之前拦截，拦截器中的 request response 已经被 spring-session 所包装
     *
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        HttpSession session = request.getSession();

        // 从 redis 中查询用户的登陆信息
        MemberTo attribute = (MemberTo) session.getAttribute(AuthServerConstant.LOGIN_USER_SESSION);

        UserInfoVo userInfoVo = new UserInfoVo();

        if (!ObjectUtils.isEmpty(attribute)) {
            // 用户已经登陆，设置用户的id
            userInfoVo.setUserId(attribute.getId());
        }

        // 获取用户的 临时 user-key
        String userKeyFormCookie = getCookieByName(request, CartConstant.USER_KEY_FOR_TEMP_COOKIE);

        userInfoVo.setUserKey(userKeyFormCookie);

        userInfoVo.setCarryTempUserKeyCookie(true);

        if (StringUtils.isEmpty(userInfoVo.getUserKey())) {
            // 用户是第一次登陆，还没有 临时购物车对应的 user-key

            String userKey = UUID.randomUUID().toString();

            /** 不可以方法执行之前让浏览器保存 cookie（因为没有效果）
             *
             *  Cookie cookie = new Cookie(CartConstant.USER_KEY_FOR_TEMP_COOKIE, userKey);
             *
             *  response.addCookie(cookie);
             *
             */
            userInfoVo.setUserKey(userKey);

            userInfoVo.setCarryTempUserKeyCookie(false);

            Cookie cookie = new Cookie(CartConstant.USER_KEY_FOR_TEMP_COOKIE, userInfoVo.getUserKey());

            cookie.setDomain("guli.com");

            cookie.setMaxAge(CartConstant.USER_KEY_FOR_TEMP_COOKIE_EXPIRE_SECONDS);

            response.addCookie(cookie);
        }


        // 将封装好的用户登陆信息放入 threadLocal，这样同一个 request，从 threadLocal 中拿到的对象就都是一样的
        // threadLocal 本质上就是一个 Map<Thread,Object> threadLocal

        THREAD_LOCAL.set(userInfoVo);

        return true;
    }


    /**
     * Note that postHandle is less useful with @ResponseBody and ResponseEntity methods for which the response is written and committed within the HandlerAdapter and before postHandle.
     * That means it is too late to make any changes to the response,
     * such as adding an extra header. For such scenarios,
     * you can implement ResponseBodyAdvice and either declare it as an Controller Advice bean or configure it directly on RequestMappingHandlerAdapter.
     *
     * 原来postHandle方法在@ResponseBody和ResponseEntity方法的场景下是无效，此时对response做任何改变，都是晚了的。
     * 官方也给出里解决方案： 实现 ResponseBodyAdvice 接口
     *
     */
    /*@Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

        //String userKey = getCookieByName(request, CartConstant.USER_KEY_FOR_TEMP_COOKIE);

        // 业务执行完之后，命令浏览器保存一个 临时 user-key
        UserInfoVo userInfoVo = THREAD_LOCAL.get();

        // 用户没有 user-key 的时候，就为他创建一个
        if(!userInfoVo.isCarryTempUserKeyCookie()){

            Cookie cookie = new Cookie(CartConstant.USER_KEY_FOR_TEMP_COOKIE, userInfoVo.getUserKey());

            cookie.setDomain("guli.com");

            cookie.setMaxAge(CartConstant.USER_KEY_FOR_TEMP_COOKIE_EXPIRE_SECONDS);

            // 太晚了，此时 response 已经响应到浏览器了，再对他做添加cookie，已经无效了
            // response.addCookie(cookie);

        }


    }*/

    private static String getCookieByName(HttpServletRequest request, String cookieName) {
        Cookie[] cookies = request.getCookies();

        if (!ObjectUtils.isEmpty(cookies)) {
            // 用户没有登陆（根据请求的 cookie 获取其user-key）
            for (Cookie cookie : cookies) {
                if (cookie.getName().equals(cookieName)) {
                    return cookie.getValue();
                }
            }
        }

        return null;
    }
}
